#include "TFModules.h"
#include <cstring>
#include <cstdlib>

using namespace tagfolder;

#if defined(__WINDOWS_PLATFORM__)
#include <windows.h>
#elif defined( __GNU_PLATFORM__)
#include <dlfcn.h>
#endif

//////////////////////////////////////////static utility methods////////////////////////
TFModule::ModuleHandler TFModule::loadModule( const char* fileName){
    static TFModule::ModuleHandler NULL_HANDLER=(TFModule::ModuleHandler)0;
    if( fileName==NULL){
        return NULL_HANDLER;
    }

    TFModule::ModuleHandler handler;

#if defined( __WINDOWS_PLATFORM__)
    //Todo!
#else
    handler = dlopen( fileName, RTLD_LAZY);
#endif

    return handler;
}

void * TFModule::parseSymbol( TFModule::ModuleHandler handler, const char* symbolName){
    if( handler!=NULL && symbolName!=NULL){
#if defined( __WINDOWS_PLATFORM__)
        //Todo!
#else
        return dlsym( handler, symbolName);
#endif
    }
    return NULL;
}

bool TFModule::closeModule( TFModule::ModuleHandler handler){

    if( handler!=NULL){
#if defined( __WINDOWS_PLATFORM__)
        //Todo!
#else
        dlclose( handler);
#endif
        return true;
    }

    return false;
}

////////////////////////////////////Module Specific methods/////////////////////

TFModule::TFModule(){
}

TFModule::TFModule( const char* fileName)
{
    if( NULL!=fileName){
        m_fileName=new char[strlen(fileName)+1];
        strcpy( m_fileName, fileName);
    }else{
        m_fileName=NULL;
    }
    load(); 
}

TFModule::~TFModule(){
    close();
}

void* TFModule::getSymbolAddress( const char* symbolName){
    return parseSymbol( m_Handler, symbolName);
}

bool TFModule::load(){
    return load( m_fileName);
}

bool TFModule::load( const char* moduleName){
    size_t sz=strlen(m_fileName);
    if( strncmp( m_fileName, moduleName, sz) !=0 ){
        m_Handler = loadModule( moduleName);
        if(m_fileName!=NULL)
            delete[] m_fileName;
        sz=strlen(moduleName);
        m_fileName = new char[sz+1];
        strncpy( m_fileName, moduleName, sz);
        m_fileName[sz]='\0';
        bool ret= ( m_Handler != ((TFModule::ModuleHandler)0));
        m_closed = !ret;
        return ret;
    }
    return true;
}

bool TFModule::close(){
    bool ret = closeModule( m_fileName);
    m_closed = ret;
    return ret;
}

bool TFModule::isClosed() const {
    return m_closed;
}

const char* TFModule::getModuleName() const{
    return m_fileName;
}

TFModule::ModuleHandler TFModule::getModuleHandler() const {
    return m_Handler;
}
